home *** CD-ROM | disk | FTP | other *** search
/ Suzy B Software 2 / Suzy B Software CD-ROM 2 (1994).iso / new_file / mintprgs / mint112s / mint112s.lzh / tosfs.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-30  |  41.2 KB  |  1,701 lines

  1. /*
  2. Copyright 1991,1992 Eric R. Smith.
  3. Copyright 1992,1993,1994 Atari Corporation.
  4. All rights reserved.
  5. */
  6.  
  7. /* a VERY simple tosfs.c 
  8.  * this one is extremely brain-damaged, but will serve OK for a
  9.  * skeleton in which to put a "real" tosfs.c
  10.  */
  11.  
  12. #include "mint.h"
  13.  
  14. /* if NEWWAY is defined, tosfs uses the new dup_cookie/release_cookie
  15.  * protocol to keep track of file cookies, instead of the old
  16.  * method of "timing"
  17.  */
  18. /* #define NEWWAY */
  19. #if 0
  20. #define COOKIE_DB(x) DEBUG(x)
  21. #else
  22. #define COOKIE_DB(x)
  23. #endif
  24.  
  25. /* if RO_FASCISM is defined, the read/write modes are enforced. This is
  26.  * a Good Thing, not fascist at all. Ask Allan Pratt why he chose
  27.  * that name sometime.
  28.  */
  29. #define RO_FASCISM
  30.  
  31. /* temporary code for debugging Falcon media change bug */
  32. #if 0
  33. #define MEDIA_DB(x) DEBUG(x)
  34. #else
  35. #define MEDIA_DB(x)
  36. #endif
  37.  
  38. /* search mask for anything OTHER THAN a volume label */
  39. #define FILEORDIR 0x37
  40.  
  41. char tmpbuf[PATH_MAX+1];
  42.  
  43. static long    ARGS_ON_STACK tos_root    P_((int drv, fcookie *fc));
  44. static long    ARGS_ON_STACK tos_lookup    P_((fcookie *dir, const char *name, fcookie *fc));
  45. static long    ARGS_ON_STACK tos_getxattr    P_((fcookie *fc, XATTR *xattr));
  46. static long    ARGS_ON_STACK tos_chattr    P_((fcookie *fc, int attrib));
  47. static long    ARGS_ON_STACK tos_chown    P_((fcookie *fc, int uid, int gid));
  48. static long    ARGS_ON_STACK tos_chmode    P_((fcookie *fc, unsigned mode));
  49. static long    ARGS_ON_STACK tos_mkdir    P_((fcookie *dir, const char *name, unsigned mode));
  50. static long    ARGS_ON_STACK tos_rmdir    P_((fcookie *dir, const char *name));
  51. static long    ARGS_ON_STACK tos_remove    P_((fcookie *dir, const char *name));
  52. static long    ARGS_ON_STACK tos_getname    P_((fcookie *root, fcookie *dir,
  53.                             char *pathname, int size));
  54. static long    ARGS_ON_STACK tos_rename    P_((fcookie *olddir, char *oldname,
  55.                     fcookie *newdir, const char *newname));
  56. static long    ARGS_ON_STACK tos_opendir    P_((DIR *dirh, int flags));
  57. static long    ARGS_ON_STACK tos_readdir    P_((DIR *dirh, char *nm, int nmlen, fcookie *));
  58. static long    ARGS_ON_STACK tos_rewinddir    P_((DIR *dirh));
  59. static long    ARGS_ON_STACK tos_closedir    P_((DIR *dirh));
  60. static long    ARGS_ON_STACK tos_pathconf    P_((fcookie *dir, int which));
  61. static long    ARGS_ON_STACK tos_dfree    P_((fcookie *dir, long *buf));
  62. static long    ARGS_ON_STACK tos_writelabel    P_((fcookie *dir, const char *name));
  63. static long    ARGS_ON_STACK tos_readlabel    P_((fcookie *dir, char *name, int namelen));
  64.  
  65. static long    ARGS_ON_STACK tos_creat    P_((fcookie *dir, const char *name, unsigned mode,
  66.                     int attrib, fcookie *fc));
  67. static DEVDRV *    ARGS_ON_STACK tos_getdev    P_((fcookie *fc, long *devsp));
  68. static long    ARGS_ON_STACK tos_open    P_((FILEPTR *f));
  69. static long    ARGS_ON_STACK tos_write    P_((FILEPTR *f, const char *buf, long bytes));
  70. static long    ARGS_ON_STACK tos_read    P_((FILEPTR *f, char *buf, long bytes));
  71. static long    ARGS_ON_STACK tos_lseek    P_((FILEPTR *f, long where, int whence));
  72. static long    ARGS_ON_STACK tos_ioctl    P_((FILEPTR *f, int mode, void *buf));
  73. static long    ARGS_ON_STACK tos_datime    P_((FILEPTR *f, short *time, int rwflag));
  74. static long    ARGS_ON_STACK tos_close    P_((FILEPTR *f, int pid));
  75. static long    ARGS_ON_STACK tos_dskchng    P_((int drv));
  76.  
  77. #ifdef NEWWAY
  78. static long    ARGS_ON_STACK tos_release P_((fcookie *fc));
  79. static long    ARGS_ON_STACK tos_dupcookie P_((fcookie *dst, fcookie *src));
  80. #endif
  81.  
  82. /* some routines from biosfs.c */
  83. extern long    ARGS_ON_STACK null_select    P_((FILEPTR *f, long p, int mode));
  84. extern void    ARGS_ON_STACK null_unselect    P_((FILEPTR *f, long p, int mode));
  85.  
  86. DEVDRV tos_device = {
  87.     tos_open, tos_write, tos_read, tos_lseek, tos_ioctl, tos_datime,
  88.     tos_close, null_select, null_unselect
  89. };
  90.  
  91. FILESYS tos_filesys = {
  92.     (FILESYS *)0,
  93.     FS_KNOPARSE | FS_NOXBIT | FS_LONGPATH,
  94.     tos_root,
  95.     tos_lookup, tos_creat, tos_getdev, tos_getxattr,
  96.     tos_chattr, tos_chown, tos_chmode,
  97.     tos_mkdir, tos_rmdir, tos_remove, tos_getname, tos_rename,
  98.     tos_opendir, tos_readdir, tos_rewinddir, tos_closedir,
  99.     tos_pathconf, tos_dfree, tos_writelabel, tos_readlabel,
  100.     nosymlink, noreadlink, nohardlink, nofscntl, tos_dskchng,
  101. #ifdef NEWWAY
  102.     tos_release, tos_dupcookie
  103. #else
  104.     0, 0
  105. #endif
  106. };
  107.  
  108. /* some utility functions and variables: see end of file */
  109. static DTABUF     *lastdta;    /* last DTA buffer we asked TOS about */
  110. static DTABUF    foo;
  111. static void do_setdta P_((DTABUF *dta));
  112. static int executable_extension P_((char *));
  113.  
  114. /* this array keeps track of which drives have been changed */
  115. /* a nonzero entry means that the corresponding drive has been changed,
  116.  * but GEMDOS doesn't know it yet
  117.  */
  118. static char drvchanged[NUM_DRIVES];
  119.  
  120. /* force TOS to see a media change */
  121. static void force_mediach P_((int drv));
  122. static long ARGS_ON_STACK Newgetbpb P_((int));
  123. static long ARGS_ON_STACK Newmediach P_((int));
  124. static long ARGS_ON_STACK Newrwabs P_((int, void *, int, int, int, long));
  125.  
  126. #ifdef NEWWAY
  127. #define NUM_INDICES 64
  128. #else
  129. #define NUM_INDICES 128
  130. #define MIN_AGE 8
  131. #endif
  132.  
  133. struct tindex {
  134.     char *name;        /* full path name */
  135.     FILEPTR *open;        /* fileptrs for this file; OR
  136.                  * count of number of open directories
  137.                  */
  138.     LOCK *locks;        /* locks on this file */
  139. /* file status */
  140.     long  size;
  141.     short time;
  142.     short date;
  143.     short attr;
  144.     short valid;        /* 1 if the above status is still valid */
  145. #ifdef NEWWAY
  146.     short links;        /* how many times index is in use */
  147. #else
  148.     short stamp;        /* age of this index, for garbage collection */
  149. #endif
  150. } gl_ti[NUM_INDICES];
  151.  
  152. /* temporary index for files found by readdir */
  153. static struct tindex tmpindex;
  154. static char tmpiname[PATH_MAX];
  155.  
  156. static struct tindex *tstrindex P_((char *s));
  157. static int tfullpath P_((char *result, struct tindex *base, const char *name));
  158. static struct tindex *garbage_collect P_((void));
  159.  
  160. #ifndef NEWWAY
  161. static short tclock;        /* #calls to tfullpath since last garbage
  162.                    collection */
  163. #endif
  164.  
  165.  
  166. #define ROOTPERMS 32
  167. #ifdef ROOTPERMS
  168. /* jr: save access permissions, owner and group for root directories.
  169.    ROOTPERMS is the number of supported drives; 'mode' has ROOTPERMSET
  170.    if it has been set  */
  171.  
  172. struct tosrootperm {
  173.     ushort uid, gid, mode;
  174. } root_perms[ROOTPERMS];
  175.  
  176. #define ROOTPERMSET    0x8000
  177. #endif
  178.  
  179. /* jr: external table, set up by getbpb in bios.c */
  180. extern unsigned short clsizb[];
  181.  
  182. #define INODE_PER_CRC
  183.  
  184. #ifdef INODE_PER_CRC
  185.  
  186. /* jr: use crc algorithm described in P1003.2, D11.2 with crctab as in
  187.    GNU-cksum. Slightly modified to return 0 for the root (instead of ~0) */
  188.  
  189. static unsigned long crctab[] = { /* CRC polynomial 0xedb88320 */
  190. 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L,
  191. 0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L,
  192. 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L,
  193. 0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L,
  194. 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
  195. 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L,
  196. 0x26d930acL, 0x51de003aL, 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL,
  197. 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL,
  198. 0x76dc4190L, 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L,
  199. 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
  200. 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L,
  201. 0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L,
  202. 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL,
  203. 0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L,
  204. 0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
  205. 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL,
  206. 0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L,
  207. 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L,
  208. 0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L,
  209. 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
  210. 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL,
  211. 0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L,
  212. 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL,
  213. 0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL,
  214. 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
  215. 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L,
  216. 0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L,
  217. 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L,
  218. 0xa00ae278L, 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, 0x4969474dL, 0x3e6e77dbL,
  219. 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
  220. 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL,
  221. 0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL
  222. };
  223.  
  224. #define UPDC32(octet, crc) (((crc) << 8) ^ crctab[((crc) >> 24) ^ (octet)])
  225.  
  226. static unsigned long
  227. filename_crc (const char *filename)
  228. {
  229.     unsigned long s = 0;
  230.     unsigned int n = 0;
  231.     
  232.     /* skip x: */
  233.     filename += 2;
  234.     
  235.     while (*filename) {
  236.         s = UPDC32 (*filename++, s);
  237.         n++;
  238.     }
  239.  
  240.     while (n != 0) {
  241.         s = UPDC32 (n & 0377, s);
  242.         n >>= 8;
  243.     }
  244.     
  245.     return s;
  246. }
  247.  
  248. #endif
  249.  
  250.  
  251. /* some extra flags for the attr field */
  252.  
  253. /*
  254.  * is a string the name of a file with executable extension?
  255.  */
  256. #define FA_EXEC 0x4000
  257. /*
  258.  * should the file be deleted when it is closed?
  259.  */
  260. #define FA_DELETE 0x2000
  261.  
  262. /*
  263.  * NOTE: call executable_extension only on a DTA name returned from
  264.  * Fsfirst(), not on an arbitrary path, for two reasons: (1) it
  265.  * expects only upper case, and (2) it looks only for the 1st extension,
  266.  * so a folder with a '.' in its name would confuse it.
  267.  */
  268.  
  269. static int
  270. executable_extension(s)
  271.     char *s;
  272. {
  273.     while (*s && *s != '.') s++;
  274.     if (!*s) return 0;
  275.     s++;
  276.     if (s[0] == 'T') {
  277.         return (s[1] == 'T' && s[2] == 'P') ||
  278.                (s[1] == 'O' && s[2] == 'S');
  279.     }
  280.     if (s[0] == 'P')
  281.         return s[1] == 'R' && s[2] == 'G';
  282.     if (s[0] == 'A')
  283.         return s[1] == 'P' && s[2] == 'P';
  284.     if (s[0] == 'G')
  285.         return s[1] == 'T' && s[2] == 'P';
  286.     return 0;
  287. }
  288.  
  289. /*
  290.  * Look in the table of tos indices to see if an index corresponding
  291.  * to this file name already exists. If so, mark it as being used
  292.  * and return it. If not, find an empty slot and make an index for
  293.  * this string. If no empty slots exist, garbage collect and
  294.  * try again.
  295.  *
  296.  * This routine is pretty dumb; we really should use a hash table
  297.  * of some sort
  298.  */
  299.  
  300. static struct tindex *tstrindex(s)
  301.     char *s;
  302. {
  303.     int i;
  304.     char *r;
  305.     struct tindex *t, *free = 0;
  306.  
  307.     assert(s != 0);
  308.     t = gl_ti;
  309.     for (i = 0; i < NUM_INDICES; i++, t++) {
  310.         if (t->name && !stricmp(t->name, s)) {
  311. #ifndef NEWWAY
  312.             t->stamp = tclock;    /* update use time */
  313. #endif
  314.             return t;
  315.         }
  316.         else if (!t->name && !free)
  317.             free = t;
  318.     }
  319.     if (!free) {
  320.         free = garbage_collect();
  321.     }
  322. #ifdef NEWWAY
  323.     if (!free) {
  324.         FORCE("tosfs: all slots in use!!");
  325.         FORCE("Links\tName");
  326.         t = gl_ti;
  327.         for (i = 0; i < NUM_INDICES; i++,t++) {
  328.             FORCE("%d\t%s", t->links, t->name);
  329.         }
  330.         FATAL("tosfs: unable to get a file name index");
  331.     }
  332. #else
  333.     if (!free) {
  334.         FATAL("tosfs: unable to get a file name index");
  335.     }
  336. #endif
  337.     r = kmalloc((long)strlen(s)+1);
  338.     if (!r) {
  339.         FATAL("tosfs: unable to allocate space for a file name");
  340.     }
  341.     strcpy(r, s);
  342.     free->name = r;
  343. #ifdef NEWWAY
  344.     free->links = 0;
  345. #else
  346.     free->stamp = tclock;
  347. #endif
  348.     free->open = 0;
  349.     free->locks = 0;
  350.  
  351. /* check to see if this file was recently returned by opendir() */
  352. #ifndef NEWWAY
  353.     if (tmpindex.valid && tclock - tmpindex.stamp < MIN_AGE &&
  354.         !stricmp(free->name, tmpindex.name)) {
  355.         free->size = tmpindex.size;
  356.         free->time = tmpindex.time;
  357.         free->date = tmpindex.date;
  358.         free->attr = tmpindex.attr;
  359.         free->valid = 1;
  360.         tmpindex.valid = 0;
  361.     } else
  362. #endif
  363.     {
  364.         free->valid = 0;
  365.         free->attr = 0;
  366.     }
  367.     return free;
  368. }
  369.  
  370. /*
  371.  * garbage collection routine: for any TOS index older than MIN_AGE,
  372.  * check through all current processes to see if it's in use. If
  373.  * not, free the corresponding string.
  374.  * Returns: a pointer to a newly freed index, or NULL.
  375.  */
  376.  
  377. /* it's unlikely that the kernel would need to hold onto a file cookie
  378.    for longer than this many calls to tstrindex() without first
  379.    saving the cookie in a directory or file pointer
  380.  */
  381.  
  382. static struct tindex *
  383. garbage_collect()
  384. {
  385.     struct tindex *free, *t;
  386.     int i;
  387. #ifndef NEWWAY
  388.     fcookie *fc, *gc;
  389.     PROC *p;
  390.     int j;
  391.     int age;
  392. #endif
  393.  
  394.     free = 0;
  395.     t = gl_ti;
  396.     for (i = 0; i < NUM_INDICES; i++,t++) {
  397.         if (!t->name) continue;
  398. #ifdef NEWWAY
  399.         if (t->links == 0) {
  400.             kfree(t->name);
  401.             t->name = 0;
  402.             if (!free) free = t;
  403.         }
  404. #else
  405.         age = tclock - t->stamp;
  406.         t->stamp = 0;
  407.         assert(age >= 0);
  408.         if (age > MIN_AGE) {
  409.         /* see if any process is using this index */
  410.             if (t->open)
  411.                 goto found_index;
  412.             for (p = proclist; p; p = p->gl_next) {
  413.                 fc = p->curdir;
  414.                 gc = p->root;
  415.                 for (j = 0; j < NUM_DRIVES; j++,fc++,gc++) {
  416.                     if (( fc->fs == &tos_filesys &&
  417.                           fc->index == (long)t ) ||
  418.                         ( gc->fs == &tos_filesys &&
  419.                           gc->index == (long)t ) )
  420.                         goto found_index;
  421.                 }
  422.             }
  423.         /* here, we couldn't find the index in use by any proc. */
  424.             kfree(t->name);
  425.             t->name = 0;
  426.             if (!free)
  427.                 free = t;
  428.         found_index:
  429.             ;
  430.         } else {
  431.     /* make sure that future garbage collections might look at this file */
  432.             t->stamp = -age;
  433.         }
  434. #endif
  435.     }
  436.  
  437. #ifndef NEWWAY
  438.     tclock = 0;    /* reset the clock */
  439.     tmpindex.valid = 0; /* expire the temporary Fsfirst buffer */
  440. #endif
  441.     return free;
  442. }
  443.  
  444. #define DIRSEP(c) ((c) == '\\')
  445.  
  446. static int
  447. tfullpath(result, basei, path)
  448.     char *result;
  449.     struct tindex *basei;
  450.     const char *path;
  451. {
  452. #define TNMTEMP 32
  453.     char *n, name[TNMTEMP+1];
  454.     int namelen, pathlen;
  455.     char *base = basei->name;
  456.     int r = 0;
  457.  
  458. #ifndef NEWWAY
  459.     basei->stamp = ++tclock;
  460.     if (tclock > 10000) {
  461.     /* garbage collect every so often whether we need it or not */
  462.         (void)garbage_collect();
  463.     }
  464. #endif
  465.     if (!*path) {
  466.         strncpy(result, base, PATH_MAX-1);
  467.         return r;
  468.     }
  469.  
  470.     strncpy(result, base, PATH_MAX-1);
  471.  
  472.     pathlen = strlen(result);
  473.  
  474. /* now path is relative to what's currently in "result" */
  475.  
  476.     while(*path) {
  477. /* get next name in path */
  478.         n = name; namelen = 0;
  479.         while (*path && !DIRSEP(*path)) {
  480. /* BUG: we really should to the translation to DOS 8.3
  481.  * format *here*, so that really long names are truncated
  482.  * correctly.
  483.  */
  484.             if (namelen < TNMTEMP) {
  485.                 *n++ = toupper(*path); path++; namelen++;
  486.             }
  487.             else
  488.                 path++;
  489.         }
  490.         *n = 0;
  491.         while (DIRSEP(*path)) path++;
  492. /* check for "." and ".." */
  493.         if (!strcmp(name, ".")) continue;
  494.         if (!strcmp(name, "..")) {
  495.             n = strrchr(result, '\\');
  496.             if (n) {
  497.                 *n = 0;
  498.                 pathlen = (int)(n - result);
  499.             }
  500.             else r = EMOUNT;
  501.             continue;
  502.         }
  503.         if (pathlen + namelen < PATH_MAX - 1) {
  504.             strcat(result, "\\");
  505.             pathlen++;
  506.  
  507.     /* make sure the name is restricted to DOS 8.3 format */
  508.             for (base = result; *base; base++)
  509.                 ;
  510.             n = name;
  511.             namelen = 0;
  512.             while (*n && *n != '.' && namelen++ < 8) {
  513.                 *base++ = *n++;
  514.                 pathlen++;
  515.             }
  516.             while (*n && *n != '.') n++;
  517.             if (*n == '.' && *(n+1) != 0) {
  518.                 *base++ = *n++;
  519.                 pathlen++;
  520.                 namelen = 0;
  521.                 while (*n && namelen++ < 3) {
  522.                     *base++ = *n++;
  523.                     pathlen++;
  524.                 }
  525.             }
  526.             *base = 0;
  527.         }
  528.     }
  529.     return r;
  530. }
  531.  
  532. static long ARGS_ON_STACK 
  533. tos_root(drv, fc)
  534.     int drv;
  535.     fcookie *fc;
  536. {
  537.     struct tindex *ti;
  538.  
  539.     ksprintf(tmpbuf, "%c:", drv+'A');
  540.     fc->fs = &tos_filesys;
  541.     fc->dev = drv;
  542.     ti = tstrindex(tmpbuf);
  543.     ti->size = ti->date = ti->time = 0;
  544.     ti->attr = FA_DIR;
  545.     ti->valid = 1;
  546.     fc->index = (long)ti;
  547.  
  548. /* if the drive has changed, make sure GEMDOS knows it! */
  549.     if (drvchanged[drv]) {
  550.         force_mediach(drv);
  551.     }
  552. #ifdef NEWWAY
  553.     ti->links++;
  554. #endif
  555.     return 0;
  556. }
  557.  
  558. static long ARGS_ON_STACK 
  559. tos_lookup(dir, name, fc)
  560.     fcookie *dir;
  561.     const char *name;
  562.     fcookie *fc;
  563. {
  564.     long r;
  565.     struct tindex *ti = (struct tindex *)dir->index;
  566.  
  567.     r = tfullpath(tmpbuf, ti, name);
  568.  
  569. /* if the name is empty or otherwise trivial, just return the directory */
  570.     if (!strcmp(ti->name, tmpbuf)) {
  571.         *fc = *dir;
  572. #ifdef NEWWAY
  573.         ti->links++;
  574.         COOKIE_DB(("tos_lookup: %s now has %d links", ti->name, ti->links));
  575. #endif 
  576.         return r;
  577.     }
  578.  
  579. /* is there already an index for this file?? If so, is it up to date?? */
  580.     ti = tstrindex(tmpbuf);
  581.     if (!ti->valid) {
  582.         if (tmpbuf[1] == ':' && tmpbuf[2] == 0) {
  583.             /* a root directory -- lookup always succeeds */
  584.             foo.dta_size = 0;
  585.             foo.dta_date = foo.dta_time = 0;
  586.             foo.dta_attrib = FA_DIR;
  587.             foo.dta_name[0] = 0;
  588.         } else {
  589.             do_setdta(&foo);
  590.             r = Fsfirst(tmpbuf, FILEORDIR);
  591.             if (r) {
  592. DEBUG(("tos_lookup: Fsfirst(%s) returned %ld", tmpbuf, r));
  593.                 return r;
  594.             }
  595.         }
  596.         ti->size = foo.dta_size;
  597.         ti->date = foo.dta_date;
  598.         ti->time = foo.dta_time;
  599.         ti->attr = foo.dta_attrib | (ti->attr & FA_DELETE);
  600.         if (executable_extension(foo.dta_name))
  601.             ti->attr |= FA_EXEC;
  602.         ti->valid = 1;
  603.     }
  604.     fc->fs = &tos_filesys;
  605.     fc->index = (long)ti;
  606.     fc->dev = dir->dev;
  607. #ifdef NEWWAY
  608.     ti->links++;
  609.     COOKIE_DB(("tos_lookup: %s now has %d links", ti->name, ti->links));
  610. #endif
  611.     return r;
  612. }
  613.  
  614. static long ARGS_ON_STACK 
  615. tos_getxattr(fc, xattr)
  616.     fcookie *fc;
  617.     XATTR *xattr;
  618. {
  619.     struct tindex *ti = (struct tindex *)fc->index;
  620.     long r;
  621. #ifndef INODE_PER_CRC
  622.     static long junkindex = 0;
  623. #endif
  624. #ifdef ROOTPERMS
  625.     struct tosrootperm *tp = NULL;
  626.     
  627.     if (fc->dev < ROOTPERMS) tp = &root_perms[fc->dev];
  628. #endif
  629.  
  630. #ifdef INODE_PER_CRC
  631.     xattr->index = filename_crc (ti->name);
  632. #else
  633.     xattr->index = junkindex++;
  634. #endif
  635.  
  636.     xattr->dev = fc->dev;
  637.     xattr->rdev = fc->dev;
  638.     xattr->nlink = 1;
  639.  
  640.     xattr->uid = xattr->gid = 0;
  641.  
  642. #ifdef ROOTPERMS
  643.     if (tp) {
  644.         xattr->uid = tp->uid;
  645.         xattr->gid = tp->gid;
  646.     }
  647. #endif
  648.  
  649. #ifndef NEWWAY
  650.     ti->stamp = ++tclock;
  651. #endif
  652.  
  653.     if (!ti->valid) {
  654.         do_setdta(&foo);
  655.         if (ti->name[2] == 0) {        /* a root directory */
  656. /* actually, this can also happen if a program tries to open a file
  657.  * with an empty name... so we should fail gracefully
  658.  */
  659.             ti->attr = FA_DIR;
  660.             ti->size = 0;
  661.             ti->date = ti->time = 0;
  662.             goto around;
  663.         }
  664.     
  665.         r = Fsfirst(ti->name, FILEORDIR);
  666.         if (r) {
  667.             DEBUG(("tosfs: search error %ld on [%s]", r, ti->name));
  668.             return r;
  669.         }
  670.         ti->size = foo.dta_size;
  671.         ti->date = foo.dta_date;
  672.         ti->time = foo.dta_time;
  673.         ti->attr = foo.dta_attrib | (ti->attr & FA_DELETE);
  674.         if (executable_extension(foo.dta_name))
  675.             ti->attr |= FA_EXEC;
  676. around:
  677.         ti->valid = 1;
  678.     }
  679.     xattr->size = ti->size;
  680.  
  681.     /* jr: if cluster size unknown, do a getbpb once */
  682.     if (fc->dev < 32 && ! clsizb[fc->dev])
  683.         getbpb (fc->dev);
  684.  
  685.     xattr->blksize = 1024;
  686.     if (fc->dev < 32 && clsizb[fc->dev])
  687.         xattr->blksize = clsizb[fc->dev];
  688.     
  689.     xattr->nblocks = (xattr->size + xattr->blksize - 1) / xattr->blksize;
  690.     xattr->mdate = xattr->cdate = xattr->adate = ti->date;
  691.     xattr->mtime = xattr->ctime = xattr->atime = ti->time;
  692.     xattr->mode = (ti->attr & FA_DIR) ? (S_IFDIR | DEFAULT_DIRMODE) :
  693.              (S_IFREG | DEFAULT_MODE);
  694.  
  695. /* TOS files have permissions rwxrwx--- */
  696.     xattr->mode &= ~(S_IROTH|S_IWOTH|S_IXOTH);
  697.  
  698. #ifdef ROOTPERMS
  699.     /* when root permissions are set, use them. For regular files,
  700.     unmask x bits */
  701.  
  702.     if (tp && (tp->mode & ROOTPERMSET)) {
  703.         xattr->mode &= ~DEFAULT_DIRMODE;
  704.         xattr->mode |= (tp->mode & DEFAULT_DIRMODE);
  705.  
  706.         if (! (ti->attr & FA_DIR))
  707.             xattr->mode &= ~(S_IXUSR|S_IXGRP|S_IXOTH);
  708.     }
  709. #endif
  710.  
  711.     if (ti->attr & FA_RDONLY) {
  712.         xattr->mode &= ~(S_IWUSR|S_IWGRP|S_IWOTH);
  713.     }
  714.  
  715.     if (ti->attr & FA_EXEC) {
  716.         xattr->mode |= (S_IXUSR|S_IXGRP|S_IXOTH);
  717.     }
  718.  
  719.     xattr->attr = ti->attr & 0xff;
  720.     return 0;
  721. }
  722.  
  723. static long ARGS_ON_STACK
  724. tos_chattr(fc, attrib)
  725.     fcookie *fc;
  726.     int attrib;
  727. {
  728.     struct tindex *ti = (struct tindex *)fc->index;
  729.  
  730.     if (ti->attr & FA_DIR) {
  731.         DEBUG(("error: attempt to change attributes of a directory"));
  732.         return EACCDN;
  733.     }
  734.     ti->valid = 0;
  735.     (void)tfullpath(tmpbuf, ti, "");
  736.     return Fattrib(tmpbuf, 1, attrib);
  737. }
  738.  
  739. static long ARGS_ON_STACK 
  740. tos_chown(dir, uid, gid)
  741.     fcookie *dir;
  742.     int uid, gid;
  743. {
  744. #ifdef ROOTPERMS
  745.     struct tindex *ti = (struct tindex *)dir->index;
  746.  
  747.     if (dir->dev < ROOTPERMS)
  748.         if (ti->name[2] == '\0')    /* root? */
  749.         {
  750.             root_perms[dir->dev].uid = uid;
  751.             root_perms[dir->dev].gid = gid;
  752.             return 0;    
  753.         }
  754.     
  755.     return EINVFN;
  756.     
  757. #else
  758.     UNUSED(dir); UNUSED(uid); UNUSED(gid);
  759.     return EINVFN;
  760. #endif
  761. }
  762.  
  763. static long ARGS_ON_STACK 
  764. tos_chmode(fc, mode)
  765.     fcookie *fc;
  766.     unsigned mode;
  767. {
  768.     int oldattr, newattr;
  769.     long r;
  770.     struct tindex *ti = (struct tindex *)fc->index;
  771.  
  772. #ifdef ROOTPERMS
  773.     if (fc->dev < ROOTPERMS) {
  774.         if (ti->name[2] == '\0') {
  775.             /* root? */
  776.             root_perms[fc->dev].mode = ROOTPERMSET | mode;
  777.             return 0;
  778.         }
  779.     }
  780. #endif
  781.  
  782.     oldattr = Fattrib(ti->name, 0, 0);
  783.     if (oldattr < 0)
  784.         return oldattr;
  785.  
  786.     ti->valid = 0;
  787.  
  788.     if (!(mode & S_IWUSR))
  789.         newattr = oldattr | FA_RDONLY;
  790.     else
  791.         newattr = oldattr & ~FA_RDONLY;
  792.     if (newattr != oldattr)
  793.         r = Fattrib(ti->name, 1, newattr);
  794.     else
  795.         r = 0;
  796.     return (r < 0) ? r : 0;
  797. }
  798.  
  799. static long ARGS_ON_STACK 
  800. tos_mkdir(dir, name, mode)
  801.     fcookie *dir;
  802.     const char *name;
  803.     unsigned mode;        /* ignored under TOS */
  804. {
  805.     UNUSED(mode);
  806.  
  807.     (void)tfullpath(tmpbuf, (struct tindex *)dir->index, name);
  808.     tmpindex.valid = 0;
  809.  
  810.     return Dcreate(tmpbuf);
  811. }
  812.  
  813. static long ARGS_ON_STACK 
  814. tos_rmdir(dir, name)
  815.     fcookie *dir;
  816.     const char *name;
  817. {
  818.     struct tindex *ti;
  819.  
  820.     (void)tfullpath(tmpbuf, (struct tindex *)dir->index, name);
  821.     ti = tstrindex(tmpbuf);
  822.     ti->valid = 0;
  823.  
  824.     return Ddelete(tmpbuf);
  825. }
  826.  
  827. static long ARGS_ON_STACK 
  828. tos_remove(dir, name)
  829.     fcookie *dir;
  830.     const char *name;
  831. {
  832.     struct tindex *ti;
  833.  
  834.     (void)tfullpath(tmpbuf, (struct tindex *)dir->index, name);
  835.  
  836.     ti = tstrindex(tmpbuf);
  837.     if (ti->open) {
  838.         DEBUG(("tos_remove: file is open, will be deleted later"));
  839.         if (ti->attr & FA_RDONLY)
  840.             return EACCDN;
  841.         ti->attr |= FA_DELETE;
  842.         return 0;
  843.     }
  844.     ti->valid = 0;
  845.     return Fdelete(tmpbuf);
  846. }
  847.  
  848. static long ARGS_ON_STACK 
  849. tos_getname(root, dir, pathname, size)
  850.     fcookie *root, *dir;
  851.     char *pathname;
  852.     int size;
  853. {
  854.     char *rootnam = ((struct tindex *)root->index)->name;
  855.     char *dirnam = ((struct tindex *)dir->index)->name;
  856.     int i;
  857.  
  858.     i = strlen(rootnam);
  859.     if (strlen(dirnam) < i) {
  860.         DEBUG(("tos_getname: root is longer than path"));
  861.         return EINTRN;
  862.     }
  863.     if (strlen(dirnam+i) < size) {
  864.         strcpy(pathname, dirnam + i);
  865. /*
  866.  * BUG: must be a better way to decide upper/lower case
  867.  */
  868.         if (curproc->domain == DOM_MINT)
  869.             strlwr(pathname);
  870.         return 0;
  871.     } else {
  872.         DEBUG(("tosfs: name too long"));
  873.         return ERANGE;
  874.     }
  875. }
  876.  
  877. static long ARGS_ON_STACK 
  878. tos_rename(olddir, oldname, newdir, newname)
  879.     fcookie *olddir;
  880.     char *oldname;
  881.     fcookie *newdir;
  882.     const char *newname;
  883. {
  884.     char newbuf[128];
  885.     struct tindex *ti;
  886.     long r;
  887.  
  888.     (void)tfullpath(tmpbuf, (struct tindex *)olddir->index, oldname);
  889.     (void)tfullpath(newbuf, (struct tindex *)newdir->index, newname);
  890.     r = Frename(0, tmpbuf, newbuf);
  891.     if (r == 0) {
  892.         ti = tstrindex(tmpbuf);
  893.         kfree(ti->name);
  894.         ti->name = kmalloc((long)strlen(newbuf)+1);
  895.         if (!ti->name) {
  896.             FATAL("tosfs: unable to allocate space for a name");
  897.         }
  898.         strcpy(ti->name, newbuf);
  899.         ti->valid = 0;
  900.     }
  901.     return r;
  902. }
  903.  
  904. #define DIR_FLAG(x)    (x->fsstuff[0])
  905. #define STARTSEARCH    0    /* opendir() was just called */
  906. #define INSEARCH    1    /* readdir() has been called at least once */
  907. #define NMFILE        2    /* no more files to read */
  908.  
  909. #define DIR_DTA(x)    ((DTABUF *)(x->fsstuff + 2))
  910. #define DIR_NAME(x)    (x->fsstuff + 32)
  911.  
  912. /*
  913.  * The directory functions are a bit tricky. What we do is have
  914.  * opendir() do Fsfirst; the first readdir() picks up this name,
  915.  * subsequent readdir()'s have to do Fsnext
  916.  */
  917.  
  918. static long ARGS_ON_STACK 
  919. tos_opendir(dirh, flags)
  920.     DIR *dirh;
  921.     int flags;
  922. {
  923.     long r;
  924.     struct tindex *t = (struct tindex *)dirh->fc.index;
  925.  
  926.     UNUSED(flags);
  927.  
  928.     (void)tfullpath(tmpbuf, t, "*.*");
  929.  
  930.     do_setdta(DIR_DTA(dirh));
  931.  
  932.     r = Fsfirst(tmpbuf, FILEORDIR);
  933.  
  934.     if (r == 0) {
  935.         t->open++;
  936.         DIR_FLAG(dirh) = STARTSEARCH;
  937.         return 0;
  938.     } else if (r == EFILNF) {
  939.         t->open++;
  940.         DIR_FLAG(dirh) = NMFILE;
  941.         return 0;
  942.     }
  943.      return r;
  944. }
  945.  
  946. static long ARGS_ON_STACK 
  947. tos_readdir(dirh, name, namelen, fc)
  948.     DIR *dirh;
  949.     char *name;
  950.     int namelen;
  951.     fcookie *fc;
  952. {
  953.     static long index = 0;
  954.     long ret;
  955.     int giveindex = dirh->flags == 0;
  956.     struct tindex *ti;
  957.     DTABUF *dta = DIR_DTA(dirh);
  958.  
  959. again:
  960.     if (DIR_FLAG(dirh) == NMFILE)
  961.         return ENMFIL;
  962.  
  963.     if (DIR_FLAG(dirh) == STARTSEARCH) {
  964.         DIR_FLAG(dirh) = INSEARCH;
  965.     } else {
  966.         assert(DIR_FLAG(dirh) == INSEARCH);
  967.         do_setdta(dta);
  968.         ret = Fsnext();
  969.         if (ret) {
  970.             DIR_FLAG(dirh) = NMFILE;
  971.             return ret;
  972.         }
  973.     }
  974.  
  975. /* don't return volume labels from readdir */
  976.     if (dta->dta_attrib == FA_LABEL) goto again;
  977.  
  978.     fc->fs = &tos_filesys;
  979.     fc->dev = dirh->fc.dev;
  980.  
  981.     (void)tfullpath(tmpiname, (struct tindex *)dirh->fc.index, DIR_NAME(dirh));
  982.  
  983.     ti = &tmpindex;
  984.     ti->name = tmpiname;
  985.     ti->valid = 1;
  986.     ti->size = dta->dta_size;
  987.     ti->date = dta->dta_date;
  988.     ti->time = dta->dta_time;
  989.     ti->attr = dta->dta_attrib;
  990. #ifndef NEWWAY
  991.     ti->stamp = tclock;
  992. #endif
  993.     if (executable_extension(dta->dta_name))
  994.         ti->attr |= FA_EXEC;
  995.     fc->index = (long)ti;
  996.  
  997.     if (giveindex) {
  998.         namelen -= (int) sizeof(long);
  999.         if (namelen <= 0) return ERANGE;
  1000.         *((long *)name) = index++;
  1001.         name += sizeof(long);
  1002.     }
  1003.     strncpy(name, DIR_NAME(dirh), namelen-1);
  1004.     name[namelen-1] = 0;
  1005.  
  1006. /* BUG: we really should do the "strlwr" operation only
  1007.  * for Dreaddir (i.e. if giveindex == 0) but
  1008.  * unfortunately some old programs rely on the behaviour
  1009.  * below
  1010.  */
  1011.     if (curproc->domain == DOM_MINT) {
  1012.         strlwr(name);
  1013.     }
  1014.     if (strlen(DIR_NAME(dirh)) >= namelen)
  1015.         return ENAMETOOLONG;
  1016. #ifdef NEWWAY
  1017.     ti->links++;
  1018.     COOKIE_DB(("tos_readdir: %s now has %d links", ti->name, ti->links));
  1019. #endif
  1020.     return 0;
  1021. }
  1022.  
  1023. static long ARGS_ON_STACK 
  1024. tos_rewinddir(dirh)
  1025.     DIR *dirh;
  1026. {
  1027.     struct tindex *ti = (struct tindex *)dirh->fc.index;
  1028.     long r;
  1029.  
  1030.     (void)tfullpath(tmpbuf, ti, "*.*");
  1031.     do_setdta(DIR_DTA(dirh));
  1032.     r = Fsfirst(tmpbuf, FILEORDIR);
  1033.     if (r == 0) {
  1034.         DIR_FLAG(dirh) = STARTSEARCH;
  1035.     } else {
  1036.         DIR_FLAG(dirh) = NMFILE;
  1037.     }
  1038.     return r;
  1039. }
  1040.  
  1041. static long ARGS_ON_STACK 
  1042. tos_closedir(dirh)
  1043.     DIR *dirh;
  1044. {
  1045.     struct tindex *t = (struct tindex *)dirh->fc.index;
  1046.  
  1047.     if (t->open == 0) {
  1048.         FATAL("t->open == 0: directory == %s", t->name);
  1049.     }
  1050.     --t->open;
  1051.     DIR_FLAG(dirh) = NMFILE;
  1052.     return 0;
  1053. }
  1054.  
  1055. static long ARGS_ON_STACK 
  1056. tos_pathconf(dir, which)
  1057.     fcookie *dir;
  1058.     int which;
  1059. {
  1060.     UNUSED(dir);
  1061.  
  1062.     switch(which) {
  1063.     case -1:
  1064.         return DP_MAXREQ;
  1065.     case DP_IOPEN:
  1066.         return 60;    /* we can only keep about this many open */
  1067.     case DP_MAXLINKS:
  1068.          return 1;    /* no hard links */
  1069.     case DP_PATHMAX:
  1070.         return PATH_MAX;
  1071.     case DP_NAMEMAX:
  1072.         return 8+3+1;
  1073.     case DP_ATOMIC:
  1074.         return 512;    /* we can write at least a sector atomically */
  1075.     case DP_TRUNC:
  1076.         return DP_DOSTRUNC;    /* DOS style file names */
  1077.     case DP_CASE:
  1078.         return DP_CASECONV;    /* names converted to upper case */
  1079.     case DP_MODEATTR:
  1080.         return FA_RDONLY|FA_HIDDEN|FA_SYSTEM|FA_LABEL|FA_CHANGED|
  1081. #ifdef ROOTPERMS
  1082.                 0666L << 8|
  1083. #endif
  1084.                 DP_FT_DIR|DP_FT_REG;
  1085.     case DP_XATTRFIELDS:
  1086.         return DP_DEV|DP_NLINK|DP_BLKSIZE|DP_SIZE|DP_NBLOCKS|DP_MTIME;
  1087.     default:
  1088.         return EINVFN;
  1089.     }
  1090. }
  1091.  
  1092. long ARGS_ON_STACK 
  1093. tos_dfree(dir, buf)
  1094.     fcookie *dir;
  1095.     long *buf;
  1096. {
  1097.     return Dfree(buf, (dir->dev)+1);
  1098. }
  1099.  
  1100. /*
  1101.  * writelabel: creates a volume label
  1102.  * readlabel: reads a volume label
  1103.  * both of these are only guaranteed to work in the root directory
  1104.  */
  1105.  
  1106. /*
  1107.  * BUG: this should first delete any old labels, so that it will
  1108.  * work with TOS <1.4
  1109.  */
  1110.  
  1111. long ARGS_ON_STACK 
  1112. tos_writelabel(dir, name)
  1113.     fcookie *dir;
  1114.     const char *name;
  1115. {
  1116.     long r;
  1117.     struct tindex *ti;
  1118.  
  1119.     (void)tfullpath(tmpbuf, (struct tindex *)dir->index, name);
  1120.     r = Fcreate(tmpbuf, FA_LABEL);
  1121.     if (r < 0) return r;
  1122.     (void)Fclose((int)r);
  1123.     ti = tstrindex(tmpbuf);
  1124.     ti->valid = 0;
  1125.     return 0;
  1126. }
  1127.  
  1128. long ARGS_ON_STACK 
  1129. tos_readlabel(dir, name, namelen)
  1130.     fcookie *dir;
  1131.     char *name;
  1132.     int namelen;
  1133. {
  1134.     long r;
  1135.     struct tindex *ti = (struct tindex *)dir->index;
  1136.  
  1137.     if (ti->name[2] != 0)        /* not a root directory? */
  1138.         return EFILNF;
  1139.  
  1140.     (void)tfullpath(tmpbuf, ti, "*.*");
  1141.     do_setdta(&foo);
  1142.     r = Fsfirst(tmpbuf, FA_LABEL);
  1143.     if (r)
  1144.         return r;
  1145.     strncpy(name, foo.dta_name, namelen-1);
  1146.     return (strlen(foo.dta_name) < namelen) ? 0 : ENAMETOOLONG;
  1147. }
  1148.  
  1149. /*
  1150.  * TOS creat: this doesn't actually create the file, rather it
  1151.  * sets up a (fake) index for the file that will be used by
  1152.  * the later tos_open call.
  1153.  */
  1154.  
  1155. static long ARGS_ON_STACK 
  1156. tos_creat(dir, name, mode, attrib, fc)
  1157.     fcookie *dir;
  1158.     const char *name;
  1159.     unsigned mode;
  1160.     int attrib;
  1161.     fcookie *fc;
  1162. {
  1163.     struct tindex *ti;
  1164.     UNUSED(mode);
  1165.  
  1166.     (void)tfullpath(tmpbuf, (struct tindex *)dir->index, name);
  1167.  
  1168.     ti = tstrindex(tmpbuf);
  1169.     ti->size = 0;
  1170.     ti->date = datestamp;
  1171.     ti->time = timestamp;
  1172.     ti->attr = attrib;
  1173.     ti->valid = 1;
  1174.  
  1175.     fc->fs = &tos_filesys;
  1176.     fc->index = (long)ti;
  1177.     fc->dev = dir->dev;
  1178. #ifdef NEWWAY
  1179.     ti->links++;
  1180.     COOKIE_DB(("tos_creat: %s now has %d links", ti->name, ti->links));
  1181. #endif
  1182.     return 0;
  1183. }
  1184.     
  1185. /*
  1186.  * TOS device driver
  1187.  */
  1188.  
  1189. static DEVDRV * ARGS_ON_STACK 
  1190. tos_getdev(fc, devsp)
  1191.     fcookie *fc;
  1192.     long *devsp;
  1193. {
  1194.     UNUSED(fc); UNUSED(devsp);
  1195.     return &tos_device;
  1196. }
  1197.  
  1198. static long ARGS_ON_STACK 
  1199. tos_open(f)
  1200.     FILEPTR *f;
  1201. {
  1202.     struct tindex *ti;
  1203.     int mode = f->flags;
  1204.     int tosmode;
  1205.     long r;
  1206.     extern int flk;        /* in main.c, set if _FLK cookie already present */
  1207.  
  1208.     ti = (struct tindex *)(f->fc.index);
  1209.     assert(ti != 0);
  1210.  
  1211. #ifndef NEWWAY
  1212.     ti->stamp = ++tclock;
  1213. #endif
  1214.     ti->valid = 0;
  1215.  
  1216. #ifndef RO_FASCISM
  1217. /* TEMPORARY HACK: change all modes to O_RDWR for files opened in
  1218.  * compatibility sharing mode. This is silly, but
  1219.  * allows broken TOS programs that write to read-only handles to continue
  1220.  * to work (it also helps file sharing, by making the realistic assumption
  1221.  * that any open TOS file can be written to). Eventually,
  1222.  * this should be tuneable by the user somehow.
  1223.  * ALSO: change O_COMPAT opens into O_DENYNONE; again, this may be temporary.
  1224.  */
  1225.     if ( (mode & O_SHMODE) == O_COMPAT ) {
  1226.         f->flags = (mode & ~(O_RWMODE|O_SHMODE)) | O_RDWR | O_DENYNONE;
  1227.     }
  1228. #endif
  1229.  
  1230. /* check to see that nobody has opened this file already in an
  1231.  * incompatible mode
  1232.  */
  1233.     if (denyshare(ti->open, f)) {
  1234.         TRACE(("tos_open: file sharing denied"));
  1235.         return EACCDN;
  1236.     }
  1237.  
  1238. /*
  1239.  * now open the file; if O_TRUNC was specified, actually
  1240.  * create the file anew.
  1241.  * BUG: O_TRUNC without O_CREAT doesn't work right. The kernel doesn't
  1242.  * use this mode, anyways
  1243.  */
  1244.  
  1245.     if (mode & O_TRUNC) {
  1246.         if (ti->open) {
  1247.             DEBUG(("tos_open: attempt to truncate an open file"));
  1248.             return EACCDN;
  1249.         }
  1250.         r = Fcreate(ti->name, ti->attr);
  1251.     } else {
  1252.         if (flk)
  1253.             tosmode = mode & (O_RWMODE|O_SHMODE);
  1254.         else
  1255.             tosmode = (mode & O_RWMODE);
  1256.         if (tosmode == O_EXEC) tosmode = O_RDONLY;
  1257.  
  1258.         r = Fopen(ti->name, tosmode );
  1259.         if (r == EFILNF && (mode & O_CREAT))
  1260.             r = Fcreate(ti->name, ti->attr);
  1261.     }
  1262.  
  1263.     if (r < 0) {
  1264. /* get rid of the index for the file, since it doesn't exist */
  1265.         kfree(ti->name);
  1266.         ti->name = 0;
  1267.         ti->valid = 0;
  1268.         return r;
  1269.     }
  1270.  
  1271.     f->devinfo = r;
  1272.  
  1273.     f->next = ti->open;
  1274.     ti->open = f;
  1275.     return 0;
  1276. }
  1277.  
  1278. static long ARGS_ON_STACK 
  1279. tos_write(f, buf, bytes)
  1280.     FILEPTR *f; const char *buf; long bytes;
  1281. {
  1282.     struct tindex *ti = (struct tindex *)f->fc.index;
  1283.  
  1284.     ti->valid = 0;
  1285.     return Fwrite((int)f->devinfo, bytes, buf);
  1286. }
  1287.  
  1288. static long ARGS_ON_STACK 
  1289. tos_read(f, buf, bytes)
  1290.     FILEPTR *f; char *buf; long bytes;
  1291. {
  1292.     return Fread((int)f->devinfo, bytes, buf);
  1293. }
  1294.  
  1295. static long ARGS_ON_STACK 
  1296. tos_lseek(f, where, whence)
  1297.     FILEPTR *f; long where; int whence;
  1298. {
  1299.     long r;
  1300.  
  1301.     r = Fseek(where, (int)f->devinfo, whence);
  1302.     return r;
  1303. }
  1304.  
  1305. static long ARGS_ON_STACK 
  1306. tos_ioctl(f, mode, buf)
  1307.     FILEPTR *f; int mode; void *buf;
  1308. {
  1309.     LOCK t, *lck, **old;
  1310.     struct flock *fl;
  1311.     long r;
  1312.     struct tindex *ti;
  1313.     extern int flk;        /* set in main.c if _FLK already installed */
  1314.  
  1315.     switch(mode) {
  1316.     case FIONREAD:
  1317.         r = Fseek (0L, (int) f->devinfo, 1);
  1318.         if (r < 0) return r;
  1319.         *(long *) buf = Fseek (0L, (int) f->devinfo, 2) - r;
  1320.         (void) Fseek (r, (int) f->devinfo, 0);
  1321.         return 0;
  1322.     case FIONWRITE:
  1323.         *((long *)buf) = 1;
  1324.         return 0;
  1325.     case FIOEXCEPT:
  1326.         *((long *)buf) = 0;
  1327.         return 0;
  1328.     case F_SETLK:
  1329.     case F_SETLKW:
  1330.     case F_GETLK:
  1331.         fl = ((struct flock *)buf);
  1332.         t.l = *fl;
  1333.         switch(t.l.l_whence) {
  1334.         case 0:
  1335.             break;
  1336.         case 1:        /* SEEK_CUR */
  1337.             r = Fseek(0L, (int)f->devinfo, 1);
  1338.             t.l.l_start += r;
  1339.             break;
  1340.         case 2:
  1341.             r = Fseek(0L, (int)f->devinfo, 1);
  1342.             t.l.l_start = Fseek(t.l.l_start, (int)f->devinfo, 2);
  1343.             (void)Fseek(r, (int)f->devinfo, 0);
  1344.             break;
  1345.         default:
  1346.             DEBUG(("Invalid value for l_whence"));
  1347.             return EINVFN;
  1348.         }
  1349. /* BUG: can't lock a file starting at >2gigabytes from the beginning */
  1350.         if (t.l.l_start < 0) t.l.l_start = 0;
  1351.         t.l.l_whence = 0;
  1352.         ti = (struct tindex *)f->fc.index;
  1353.  
  1354.         if (mode == F_GETLK) {
  1355.             lck = denylock(ti->locks, &t);
  1356.             if (lck)
  1357.                 *fl = lck->l;
  1358.             else
  1359.                 fl->l_type = F_UNLCK;
  1360.             return 0;
  1361.         }
  1362.  
  1363.         if (t.l.l_type == F_UNLCK) {
  1364.         /* try to find the lock */
  1365.             old = &ti->locks;
  1366.             lck = *old;
  1367.             while (lck) {
  1368.                 if (lck->l.l_pid == curproc->pid &&
  1369.                     lck->l.l_start == t.l.l_start &&
  1370.                     lck->l.l_len == t.l.l_len) {
  1371.         /* found it -- remove the lock */
  1372.                     *old = lck->next;
  1373.                     TRACE(("tosfs: unlocked %s: %ld + %ld",
  1374.                         ti->name, t.l.l_start, t.l.l_len));
  1375.                     if (flk)
  1376.                         (void)Flock((int)f->devinfo, 1,
  1377.                             t.l.l_start, t.l.l_len);
  1378.                 /* wake up anyone waiting on the lock */
  1379.                     wake(IO_Q, (long)lck);
  1380.                     kfree(lck);
  1381.                     break;
  1382.                 }
  1383.                 old = &lck->next;
  1384.                 lck = lck->next;
  1385.             }
  1386.             return lck ?  0 : ENSLOCK;
  1387.         }
  1388.         TRACE(("tosfs: lock %s: %ld + %ld", ti->name,
  1389.             t.l.l_start, t.l.l_len));
  1390.         do {
  1391.         /* see if there's a conflicting lock */
  1392.             while ((lck = denylock(ti->locks, &t)) != 0) {
  1393.                 DEBUG(("tosfs: lock conflicts with one held by %d",
  1394.                     lck->l.l_pid));
  1395.                 if (mode == F_SETLKW) {
  1396.                     sleep(IO_Q, (long)lck);        /* sleep a while */
  1397.                 }
  1398.                 else
  1399.                     return ELOCKED;
  1400.             }
  1401.         /* if not, add this lock to the list */
  1402.             lck = kmalloc(SIZEOF(LOCK));
  1403.             if (!lck) return ENSMEM;
  1404.         /* see if other _FLK code might object */
  1405.             if (flk) {
  1406.                 r = Flock((int)f->devinfo, 0, t.l.l_start, t.l.l_len);
  1407.                 if (r) {
  1408.                     kfree(lck);
  1409.                     if (mode == F_SETLKW && r == ELOCKED) {
  1410.                         yield();
  1411.                         lck = NULL;
  1412.                     }
  1413.                     else
  1414.                         return r;
  1415.                 }
  1416.             }
  1417.         } while (!lck);
  1418.         lck->l = t.l;
  1419.         lck->l.l_pid = curproc->pid;
  1420.         lck->next = ti->locks;
  1421.         ti->locks = lck;
  1422.     /* mark the file as being locked */
  1423.         f->flags |= O_LOCK;
  1424.         return 0;
  1425.     }
  1426.     return EINVFN;
  1427. }
  1428.  
  1429. static long ARGS_ON_STACK 
  1430. tos_datime(f, timeptr, rwflag)
  1431.     FILEPTR *f;
  1432.     short *timeptr;
  1433.     int rwflag;
  1434. {
  1435.     if (rwflag) {
  1436.         struct tindex *ti = (struct tindex *)f->fc.index;
  1437.         ti->valid = 0;
  1438.     }
  1439.     return Fdatime(timeptr, (int)f->devinfo, rwflag);
  1440. }
  1441.  
  1442. static long ARGS_ON_STACK 
  1443. tos_close(f, pid)
  1444.     FILEPTR *f;
  1445.     int pid;
  1446. {
  1447.     LOCK *lck, **oldl;
  1448.     struct tindex *t;
  1449.     FILEPTR **old, *p;
  1450.     long r = 0;
  1451.     extern int flk;        /* set in main.c */
  1452.  
  1453.     t = (struct tindex *)(f->fc.index);
  1454. /* if this handle was locked, remove any locks held by the process
  1455.  */
  1456.     if (f->flags & O_LOCK) {
  1457.         TRACE(("tos_close: releasing locks (file mode: %x)", f->flags));
  1458.         oldl = &t->locks;
  1459.         lck = *oldl;
  1460.         while (lck) {
  1461.             if (lck->l.l_pid == pid) {
  1462.                 *oldl = lck->next;
  1463.                 if (flk)
  1464.                     (void)Flock((int)f->devinfo, 1,
  1465.                         lck->l.l_start, lck->l.l_len);
  1466.                 wake(IO_Q, (long)lck);
  1467.                 kfree(lck);
  1468.             } else {
  1469.                 oldl = &lck->next;
  1470.             }
  1471.             lck = *oldl;
  1472.         }
  1473.     }
  1474.  
  1475.     if (f->links <= 0) {
  1476. /* remove f from the list of open file pointers on this index */
  1477.         t->valid = 0;
  1478.         old = &t->open;
  1479.         p = t->open;
  1480.         while (p && p != f) {
  1481.             old = &p->next;
  1482.             p = p->next;
  1483.         }
  1484.         assert(p);
  1485.         *old = f->next;
  1486.         f->next = 0;
  1487.         r = Fclose((int)f->devinfo);
  1488.  
  1489. /* if the file was marked for deletion, delete it */
  1490.         if (!t->open) {
  1491.             if (t->attr & FA_DELETE) {
  1492.                 (void)Fdelete(t->name);
  1493.                 t->name = 0;
  1494.             }
  1495.         }
  1496.     }
  1497.     return r;
  1498. }
  1499.  
  1500. /*
  1501.  * check for disk change: called by the kernel if Mediach returns a
  1502.  * non-zero value
  1503.  */
  1504.  
  1505. long ARGS_ON_STACK 
  1506. tos_dskchng(drv)
  1507.     int drv;
  1508. {
  1509.     char dlet;
  1510.     int i;
  1511.     struct tindex *ti;
  1512.     FILEPTR *f, *nextf;
  1513.  
  1514.     dlet = 'A' + drv;
  1515. MEDIA_DB(("tos_dskchng(%c)", dlet));
  1516.     ti = gl_ti;
  1517.     for (i = 0; i < NUM_INDICES; i++, ti++) {
  1518.         if (ti->name && ti->name[0] == dlet) {
  1519. #ifdef NEWWAY
  1520.     /* only free the name if this index not used by any cookie */
  1521.             if (ti->links != 0)
  1522.                 ti->valid = 0;
  1523.             else
  1524. #endif /* NEWWAY */
  1525.             {
  1526.                 kfree(ti->name);
  1527.                 ti->name = 0;
  1528.             }
  1529.             if (!(ti->attr & FA_DIR)) {
  1530.                 nextf = ti->open;
  1531.                 while ( (f = nextf) != 0 ) {
  1532.                     nextf = f->next;
  1533.                     f->next = 0;
  1534.                 }
  1535.             }
  1536.             ti->open = 0;
  1537.     /* if there are any cookies pointing at this name, they're not
  1538.      * valid any more, so we will *want* to get an error if they're
  1539.      * used.
  1540.      */
  1541.         }
  1542.     }
  1543.     tmpindex.valid = 0;
  1544. /*
  1545.  * OK, make sure that GEMDOS knows to look for a change if we
  1546.  * ever use this drive again.
  1547.  */
  1548.     drvchanged[drv] = 1;
  1549.     return 1;
  1550. }
  1551.  
  1552. #ifdef NEWWAY
  1553. /* release/copy file cookies; these functions exist to keep
  1554.  * track of whether or not the kernel is still using a file
  1555.  */
  1556. long
  1557. tos_release(fc)
  1558.     fcookie *fc;
  1559. {
  1560.     struct tindex *ti = (struct tindex *)fc->index;
  1561.  
  1562.     if (ti->links <= 0) {
  1563.         FATAL("tos_release: link count of `%s' is %d", ti->name, ti->links);
  1564.     }
  1565.     ti->links--;
  1566.     COOKIE_DB(("tos_release: %s now has %d links", ti->name, ti->links));
  1567.     return 0;
  1568. }
  1569.  
  1570. long
  1571. tos_dupcookie(dest, src)
  1572.     fcookie *dest, *src;
  1573. {
  1574.     struct tindex *ti = (struct tindex *)src->index;
  1575.  
  1576.     if (ti->links <= 0) {
  1577.         FATAL("tos_dupcookie: link count of %s is %d", ti->name, ti->links);
  1578.     }
  1579.     ti->links++;
  1580.     COOKIE_DB(("tos_dupcookie: %s now has %d links", ti->name, ti->links));
  1581.     *dest = *src;
  1582.     return 0;
  1583. }
  1584. #endif
  1585.  
  1586. /*
  1587.  * utility function: sets the TOS DTA, and also records what directory
  1588.  * this was in. This is just to save us a call into the kernel if the
  1589.  * correct DTA has already been set.
  1590.  */
  1591.  
  1592. static void
  1593. do_setdta(dta)
  1594.     DTABUF *dta;
  1595. {
  1596.     if (dta != lastdta) {
  1597.         Fsetdta(dta);
  1598.         lastdta = dta;
  1599.     }
  1600. }
  1601.  
  1602. /*
  1603.  * routines for forcing a media change on drive "drv"
  1604.  */
  1605.  
  1606. static int chdrv;
  1607.  
  1608. /* new Getbpb function: when this is called, all the other
  1609.  * vectors can be un-installed
  1610.  */
  1611.  
  1612. static long ARGS_ON_STACK (*Oldgetbpb) P_((int));
  1613. static long ARGS_ON_STACK (*Oldmediach) P_((int));
  1614. static long ARGS_ON_STACK (*Oldrwabs) P_((int, void *, int, int, int, long));
  1615.  
  1616. static long  ARGS_ON_STACK
  1617. Newgetbpb(d)
  1618.     int d;
  1619. {
  1620.     if (d == chdrv) {
  1621. MEDIA_DB(("Newgetbpb(%c)", d+'A'));
  1622. if (Oldgetbpb == Newgetbpb) {
  1623. MEDIA_DB(("AARGH!!! BAD BPBs"));
  1624. }
  1625.         *((Func *)0x472L) = Oldgetbpb;
  1626.         *((Func *)0x476L) = Oldrwabs;
  1627.         *((Func *)0x47eL) = Oldmediach;
  1628.     }
  1629.     return (*Oldgetbpb)(d);
  1630. }
  1631.  
  1632. static long ARGS_ON_STACK
  1633. Newmediach(d)
  1634.     int d;
  1635. {
  1636.     if (d == chdrv) {
  1637. MEDIA_DB(("Newmediach(%c)", d+'A'));
  1638.         return 2;
  1639.     }
  1640.     return (*Oldmediach)(d);
  1641. }
  1642.  
  1643. static long ARGS_ON_STACK
  1644. Newrwabs(mode, buf, num, recno, dev, l)
  1645.     int mode;
  1646.     void *buf;
  1647.     int num, recno, dev;
  1648.     long l;
  1649. {
  1650.     if (dev == chdrv) {
  1651. MEDIA_DB(("Newrwabs"));
  1652.         return E_CHNG;
  1653.     }
  1654.     return (*Oldrwabs)(mode, buf, num, recno, dev, l);
  1655. }
  1656.  
  1657. static void
  1658. force_mediach(d)
  1659.     int d;
  1660. {
  1661. #ifdef FSFIRST_MEDIACH
  1662.     static char fname[] = "X:\\*.*";
  1663. #else
  1664.     long r;
  1665.     static char fname[] = "X:\\X";
  1666. #endif
  1667.     TRACE(("tosfs: disk change drive %c", d+'A'));
  1668. MEDIA_DB(("forcing media change on %c", d+'A'));
  1669.  
  1670.     chdrv = d;
  1671.     Oldrwabs = *((Func *)0x476L);
  1672.     Oldgetbpb = *((Func *)0x472L);
  1673.     Oldmediach = *((Func *)0x47eL);
  1674.  
  1675.     if (Oldrwabs == Newrwabs || Oldgetbpb == Newgetbpb ||
  1676.         Oldmediach == Newmediach) {
  1677.         FORCE("tosfs: error in media change code");
  1678.     } else {
  1679.         *((Func *)0x476L) = Newrwabs;
  1680.         *((Func *)0x472L) = Newgetbpb;
  1681.         *((Func *)0x47eL) = Newmediach;
  1682.     }
  1683.  
  1684.     fname[0] = d + 'A';
  1685. MEDIA_DB(("calling GEMDOS"));
  1686. #ifdef FSFIRST_MEDIACH
  1687.     (void)Fsfirst(fname, 8);
  1688. #else    
  1689.     r = Fopen(fname, 0);
  1690.     if (r >= 0) Fclose((int)r);
  1691. #endif
  1692. MEDIA_DB(("done calling GEMDOS"));
  1693.     drvchanged[d] = 0;
  1694.     if ( *((Func *)0x476L) == Newrwabs ) {
  1695.         DEBUG(("WARNING: media change not performed correctly"));
  1696.         *((Func *)0x472L) = Oldgetbpb;
  1697.         *((Func *)0x476L) = Oldrwabs;
  1698.         *((Func *)0x47eL) = Oldmediach;
  1699.     }
  1700. }
  1701.